#include "WebsocketClient.hpp"
#include <spdlog/spdlog.h>
#include <regex>
#include <cstring>

namespace beast=boost::beast;
namespace net=boost::asio;
using tcp=boost::asio::ip::tcp;

WebsocketClinet::WebsocketClinet(const std::string& Host,const std::string & Req)
  : ioc()
  , ws(ioc)
  , funcDataCallback(nullptr)
{
  spdlog::info("websocketclient构造");
  std::regex reg(R"(http://(\S+):([0-9]+))");
  std::smatch res;

  std::string ipaddr;
  unsigned short port;
  if(std::regex_match(Host,res,reg))
  {
    if(res.size()==3)
    {
      ipaddr=res[1];
      port=std::stoi(res[2]);
    }
    else
      throw std::runtime_error("Websocket无法解析主机名");
  }
  else
    throw std::runtime_error("Websocket解析主机名错误");

  try
  {
    tcp::endpoint endpoint={net::ip::make_address_v4(ipaddr),port};
    //tcp::resolver resolve(ioc);
    //auto const result=resolve.resolve({addr,port});
    //spdlog::info("解析后获得的IP数量 {}",result.size());
    //auto debug_i=result.begin()->endpoint().address().to_string();
    //auto ep=net::connect(ws.next_layer(),endpoint);
    boost::beast::get_lowest_layer(ws).connect(endpoint);
    ws.handshake(Host,Req);
    ws.set_option(beast::websocket::stream_base::decorator(
    [](beast::websocket::request_type& req)
    {
        req.set(beast::http::field::user_agent,
            std::string(BOOST_BEAST_VERSION_STRING) +
                " websocket-client-coro");
    }));
    ws.binary(true);
  }
  catch(std::exception const & e)
  {
    spdlog::error("Websocket连接创建失败 {}",e.what());
    throw;
  }
}

WebsocketClinet::~WebsocketClinet()
{
  spdlog::info("websocketclient退出");
  ws.close(beast::websocket::close_code::normal);
  if(readMsgThread.joinable())
  {
    readMsgThread.request_stop();
    readMsgThread.join();
  }
}

void WebsocketClinet::BootReadCallback(std::function<void(const char* data,std::size_t size)> func)
{
  funcDataCallback=func;
  readMsgThread=std::jthread([this](std::stop_token token){
      beast::flat_buffer buffer;
      while(!token.stop_requested())
      {
        {
          std::lock_guard<std::mutex> lck(wsMut);
          try
          {
            ws.read(buffer);
          }
          catch(...)
          {
            return;
          }
        }
        funcDataCallback((const char*)buffer.data().data(),buffer.data().size());
        buffer.consume(buffer.size());
      }
    });
}

std::pair<char*,std::size_t> WebsocketClinet::ReadData()
{
  beast::flat_buffer buffer;
  {
    std::lock_guard<std::mutex> lck(wsMut);
    ws.read(buffer);
  }
  std::pair<char*,std::size_t> ret={new char[buffer.data().size()],buffer.data().size()};
  memcpy(ret.first,buffer.data().data(),buffer.data().size());
  return ret;
}

void WebsocketClinet::WriteData(const char* data,std::size_t size)
{
  std::lock_guard<std::mutex> lck(wsMut);
  net::const_buffer buf(data,size);
  ws.text(false);
  ws.write(buf);
}

void WebsocketClinet::WriteText(const char* data,std::size_t size)
{
  std::lock_guard<std::mutex> lck(wsMut);
  net::const_buffer buf(data,size);
  ws.text(true);
  ws.write(buf);
}
